package com.zlm.tools.test;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @author zlm
 * @date 2023/8/16
 */
public class CompletableFutureDemo {

    private static final Executor EXECUTOR = Executors.newFixedThreadPool(10);

    public static void main(String[] args) {
        CompletableFutureDemo demo = new CompletableFutureDemo();
        List<Integer> result = demo.parallelFutureJoin(Arrays.asList(1, 2, 3, 4, 5), num -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return (num * 2);
        }, (e, num) -> {
            return -1;
        },EXECUTOR);

        System.out.println(result);

    }

    /**
     * 创建并行任务并执行
     * @param list                  数据
     * @param function              逻辑
     * @param exceptionHandle       异常处理
     * @param executor              线程池
     * @param <S>                   数据类型
     * @param <T>                   返回类型
     * @return                      结果
     */
    public <S,T> List<T> parallelFutureJoin(Collection<S> list, Function<S,T> function, BiFunction<Throwable,S,T> exceptionHandle,Executor executor){
        List<CompletableFuture<T>> collectFuture = list.stream()
                .map(s -> this.createFuture(() -> function.apply(s), e -> exceptionHandle.apply(e, s),executor))
                .collect(Collectors.toList());
        return collectFuture.stream()
                .map(CompletableFuture::join)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 创建CompletableFuture对象
     * @param function
     * @param exceptionHandle
     * @param executor
     * @return
     * @param <T>
     */
    private <T> CompletableFuture<T> createFuture(Supplier<T> function, Function<Throwable,T> exceptionHandle,Executor executor){

        return CompletableFuture.supplyAsync(function,executor).exceptionally(exceptionHandle);
    }



}
